Skip to content

gh-129289: fix subclass of asyncio.Task not propagating __del__() cau…#129804

Closed
tom-pytel wants to merge 4 commits into
python:mainfrom
tom-pytel:fix-issue-129289
Closed

gh-129289: fix subclass of asyncio.Task not propagating __del__() cau…#129804
tom-pytel wants to merge 4 commits into
python:mainfrom
tom-pytel:fix-issue-129289

Conversation

@tom-pytel

@tom-pytel tom-pytel commented Feb 7, 2025

Copy link
Copy Markdown
Contributor

Its been a bit and I didn't see anyone pick this up, so at least fix the segfault in this case.

Comment thread Modules/_asynciomodule.c
if (PyErr_WarnEx(PyExc_Warning, "subclasses of asyncio.Task must propagate __del__()", 1) < 0) {
PyErr_Clear();
}
_PyObject_ResurrectStart(self);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you want to do it like this. You probably want PyObject_CallFinalizerFromDealloc.

@tom-pytel tom-pytel Feb 7, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look above, this only happens if PyObject_CallFinalizerFromDealloc executes but the Task.__del__() was not called, so this needs to do this stuff which normally happens in PyObject_CallFinalizerFromDealloc but explicitly. Agree is not cleanest, but did not see better option.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah wait, I didn't see that it's already called before, but manually trying to resurrect like this seems error-prone.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd lean towards just emitting the warning, and then refactoring as needed to prevent a crash if the finalizer wasn't called.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said, agreed is a bit hacky, though is used in a few other places (codeobject, dictobject, funcobject). Currently the alternative is segfault in this case so your call.

@ZeroIntensity ZeroIntensity Feb 7, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, and I'd also expect strings to do this as well--but that's not the point. Those are all core interpreter types, asyncio.Task isn't. I'll let @kumaraditya303 make the call here, but IMO, types should always behave in a sane way when both finalized and non-finalized.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, a simpler way to prevent the segfault without needing to resurrect and call the finalizer would be to just remove the task from the linked list. This has the drawback of not calling callbacks but is a less messy way to keep going. Would you prefer this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a better fix in works, I'll post in sometime.

@tom-pytel tom-pytel closed this Feb 7, 2025
@tom-pytel tom-pytel deleted the fix-issue-129289 branch March 4, 2025 12:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants